import os
import requests
import zipfile
import threading
import shutil
import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
from pathlib import Path
import subprocess
import json
import tempfile

class FFmpegConfigurator:
    def get_long_path_name(self, path):
        """获取Windows长路径名"""
        path_str = str(path)
        # 尝试将8.3格式转换为完整格式
        if "ADMINI~1" in path_str:
            # 假设ADMINI~1对应Administrator
            path_str = path_str.replace("ADMINI~1", "Administrator")
        return path_str
    
    # 静态变量定义
    app_data_dir = Path(os.getenv('APPDATA')) / "FFmpegInstaller"
    temp_dir = Path(tempfile.gettempdir()) / "FFmpegDownload"
    download_path = temp_dir / "ffmpeg.zip"
    extract_path = app_data_dir / "ffmpeg"
    config_file = app_data_dir / "config.json"
    ffmpeg_url = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip"
    
    def __init__(self, root):
        self.root = root
        self.root.title("FFmpeg 环境配置工具")
        self.root.geometry("700x500")
        self.root.resizable(True, True)
        
        # 确保目录存在
        FFmpegConfigurator.app_data_dir.mkdir(parents=True, exist_ok=True)
        FFmpegConfigurator.temp_dir.mkdir(parents=True, exist_ok=True)
        
        # 创建界面
        self.create_widgets()
        
        # 初始检查
        self.check_ffmpeg_ui()
        
    def create_widgets(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 标题
        title_label = ttk.Label(main_frame, text="FFmpeg 环境配置工具", font=("Arial", 16, "bold"))
        title_label.grid(row=0, column=0, columnspan=2, pady=(0, 10))
        
        # 状态区域
        status_frame = ttk.LabelFrame(main_frame, text="当前状态", padding="5")
        status_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 10))
        
        self.status_label = ttk.Label(status_frame, text="正在检查 FFmpeg 配置...")
        self.status_label.grid(row=0, column=0, sticky=tk.W)
        
        # 进度条
        self.progress_bar = ttk.Progressbar(main_frame, mode='determinate')
        self.progress_bar.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 10))
        
        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=3, column=0, columnspan=2, pady=(0, 10))
        
        self.check_button = ttk.Button(button_frame, text="检查 FFmpeg", command=self.check_ffmpeg_ui)
        self.check_button.pack(side=tk.LEFT, padx=(0, 5))
        
        self.download_button = ttk.Button(button_frame, text="下载并配置 FFmpeg", command=self.start_download)
        self.download_button.pack(side=tk.LEFT, padx=5)
        self.download_button.config(state=tk.DISABLED)
        
        self.cancel_button = ttk.Button(button_frame, text="取消", command=self.cancel_download)
        self.cancel_button.pack(side=tk.LEFT, padx=(5, 0))
        self.cancel_button.config(state=tk.DISABLED)
        
        # 路径信息
        path_frame = ttk.LabelFrame(main_frame, text="路径信息", padding="5")
        path_frame.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 10))
        
        ttk.Label(path_frame, text=f"下载目录: {self.get_long_path_name(FFmpegConfigurator.temp_dir)}").pack(anchor=tk.W)
        ttk.Label(path_frame, text=f"安装目录: {self.get_long_path_name(FFmpegConfigurator.app_data_dir)}").pack(anchor=tk.W)
        
        # 日志区域
        log_frame = ttk.LabelFrame(main_frame, text="日志输出", padding="5")
        log_frame.grid(row=5, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        self.log_text = scrolledtext.ScrolledText(log_frame, height=15, width=80)
        self.log_text.pack(fill=tk.BOTH, expand=True)
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(5, weight=1)
        
        # 下载线程
        self.download_thread = None
        self.stop_download = False
        
    def log_message(self, message):
        """向日志添加消息"""
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)
        print(message)  # 同时输出到控制台
        
    @staticmethod
    def check_ffmpeg():
        """检查FFmpeg是否可用，如果可用则返回True"""
        # 首先检查ffmpeg命令是否可用（系统可能已经安装了ffmpeg）
        if FFmpegConfigurator.test_ffmpeg():
            return True
        
        # 如果系统没有安装，检查是否已经配置过
        if FFmpegConfigurator.is_ffmpeg_configured():
            ffmpeg_path = FFmpegConfigurator.get_configured_ffmpeg_path()
            if ffmpeg_path and (ffmpeg_path / "bin" / "ffmpeg.exe").exists():
                # 添加到当前环境
                bin_path = str(ffmpeg_path / "bin")
                os.environ["PATH"] = bin_path + os.pathsep + os.environ["PATH"]
                
                # 再次检查配置后的ffmpeg是否可用
                if FFmpegConfigurator.test_ffmpeg():
                    return True
        
        # 如果都不行，返回False
        return False
        
    def check_ffmpeg_ui(self):
        """检查FFmpeg并更新UI状态"""
        if FFmpegConfigurator.check_ffmpeg():
            self.status_label.config(text="FFmpeg 已正确配置!")
            self.log_message("FFmpeg 已正确安装!")
            self.download_button.config(state=tk.DISABLED)
            return True
        else:
            self.status_label.config(text="FFmpeg 未正确配置")
            self.log_message("FFmpeg 未安装或未正确配置")
            self.download_button.config(state=tk.NORMAL)
            return False
        
    @staticmethod
    def test_ffmpeg():
        """测试FFmpeg是否可用"""
        try:
            result = subprocess.run(["ffmpeg", "-version"], 
                                  capture_output=True, 
                                  text=True, 
                                  timeout=5,
                                  creationflags=subprocess.CREATE_NO_WINDOW)
            return "ffmpeg version" in result.stdout
        except (subprocess.CalledProcessError, FileNotFoundError, subprocess.TimeoutExpired):
            return False
        
    @staticmethod
    def is_ffmpeg_configured():
        """检查是否已经配置过FFmpeg"""
        config_file = Path(os.path.join(os.getenv('APPDATA'), "FFmpegInstaller", "config.json"))
        return config_file.exists()
        
    @staticmethod
    def get_configured_ffmpeg_path():
        """获取已配置的FFmpeg路径"""
        try:
            config_file = Path(os.path.join(os.getenv('APPDATA'), "FFmpegInstaller", "config.json"))
            with open(config_file, 'r') as f:
                config = json.load(f)
                return Path(config.get('ffmpeg_path', ''))
        except:
            return None
            
    def save_config(self, ffmpeg_path):
        """保存配置"""
        config = {
            'ffmpeg_path': str(ffmpeg_path),
            'version': '1.0'
        }
        with open(FFmpegConfigurator.config_file, 'w') as f:
            json.dump(config, f)
            
    def start_download(self):
        """开始下载FFmpeg"""
        self.log_message("开始下载 FFmpeg...")
        self.log_message(f"下载文件将保存到: {FFmpegConfigurator.download_path}")
        self.progress_bar['value'] = 0
        self.download_button.config(state=tk.DISABLED)
        self.cancel_button.config(state=tk.NORMAL)
        self.check_button.config(state=tk.DISABLED)
        self.stop_download = False
        
        # 创建并启动下载线程
        self.download_thread = threading.Thread(target=self.download_and_install)
        self.download_thread.daemon = True
        self.download_thread.start()
        
        # 启动进度检查
        self.check_progress()
        
    def download_and_install(self):
        """下载并安装FFmpeg"""
        try:
            # 检查是否已下载且文件完整（大于90MB）
            if FFmpegConfigurator.download_path.exists():
                file_size = FFmpegConfigurator.download_path.stat().st_size
                if file_size >= 90 * 1024 * 1024:  # 90MB
                    self.log_message("发现已下载的完整文件，跳过下载")
                    self.update_progress(100)
                else:
                    self.log_message(f"发现不完整的下载文件 ({file_size // (1024*1024)}MB)，重新下载")
                    FFmpegConfigurator.download_path.unlink()  # 删除不完整文件
            else:
                # 下载文件
                self.log_message(f"开始下载: {FFmpegConfigurator.ffmpeg_url}")
                response = requests.get(FFmpegConfigurator.ffmpeg_url, stream=True)
                total_size = int(response.headers.get('content-length', 0))
                block_size = 1024  # 1 KB
                downloaded = 0
                
                with open(FFmpegConfigurator.download_path, 'wb') as f:
                    for data in response.iter_content(block_size):
                        if self.stop_download:
                            self.log_message("下载已取消")
                            return
                        downloaded += len(data)
                        f.write(data)
                        progress = int((downloaded / total_size) * 100) if total_size > 0 else 0
                        self.update_progress(progress)
            
            # 解压文件
            self.log_message("开始解压文件...")
            # 确保解压目录存在
            FFmpegConfigurator.extract_path.mkdir(parents=True, exist_ok=True)
            
            with zipfile.ZipFile(FFmpegConfigurator.download_path, 'r') as zip_ref:
                zip_ref.extractall(FFmpegConfigurator.extract_path)
           
            # 找到实际的FFmpeg目录（ZIP文件中可能有一个顶层目录）
            ffmpeg_dir = None
            for item in FFmpegConfigurator.extract_path.iterdir():
                if item.is_dir() and "ffmpeg" in item.name.lower():
                    ffmpeg_dir = item
                    break
            
            if not ffmpeg_dir:
                ffmpeg_dir = FFmpegConfigurator.extract_path
                
            # 保存配置信息
            self.save_config(ffmpeg_dir)
            
            # 设置环境变量
            bin_path = str(ffmpeg_dir / "bin")
            os.environ["PATH"] = bin_path + os.pathsep + os.environ["PATH"]
                
            self.log_message("FFmpeg 配置完成!")
            self.download_finished(True)
            
        except Exception as e:
            self.log_message(f"错误: {str(e)}")
            import traceback
            self.log_message(traceback.format_exc())
            self.download_finished(False)
    
    def update_progress(self, value):
        """更新进度条"""
        self.progress_bar['value'] = value
        
    def check_progress(self):
        """检查下载进度"""
        if self.download_thread and self.download_thread.is_alive():
            self.root.after(100, self.check_progress)
        
    def download_finished(self, success):
        """下载完成处理"""
        self.cancel_button.config(state=tk.DISABLED)
        self.check_button.config(state=tk.NORMAL)
        
        if success:
            self.log_message("下载和解压完成!")
            # 重新检查FFmpeg配置
            self.check_ffmpeg_ui()
            messagebox.showinfo("完成", "FFmpeg 下载和配置完成!")
        else:
            self.download_button.config(state=tk.NORMAL)
            messagebox.showerror("错误", "FFmpeg 下载或配置失败!")
            
    def cancel_download(self):
        """取消下载"""
        self.stop_download = True
        self.log_message("下载已取消")
        self.cancel_button.config(state=tk.DISABLED)
        self.download_button.config(state=tk.NORMAL)
        self.check_button.config(state=tk.NORMAL)
        
    def on_closing(self):
        """窗口关闭事件"""
        if self.download_thread and self.download_thread.is_alive():
            if messagebox.askokcancel("确认退出", "下载仍在进行中，确定要退出吗?"):
                self.stop_download = True
                self.download_thread.join(timeout=1.0)
                self.root.destroy()
        else:
            self.root.destroy()

    @staticmethod
    def setup_ffmpeg():
        """使用FFmpegConfigurator GUI工具来配置FFmpeg环境"""
        
        # 检查FFmpeg是否已经可用
        if FFmpegConfigurator.check_ffmpeg():
            print("检测到系统中已安装FFmpeg")
            return True
        
        # 启动FFmpegConfigurator GUI工具
        try:
            root = tk.Tk()
            root.withdraw()  # 隐藏主窗口
            
            # 询问用户是否要启动配置工具
            response = messagebox.askyesno(
                "FFmpeg未找到",
                "检测到您的系统中未安装FFmpeg，这是视频剪辑功能必需的组件。\n\n"
                "是否启动FFmpeg配置工具来自动下载和配置FFmpeg？\n\n"
                "(下载大小约为100MB，需要网络连接)"
            )
            
            if not response:
                messagebox.showerror("缺少FFmpeg", "无法继续，FFmpeg是视频剪辑功能的必需组件。\n\n"
                                   "请手动下载并安装FFmpeg：https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip")
                return False
            
            # 启动配置工具
            root.destroy()  # 关闭临时窗口
            
            # 创建主配置窗口
            config_root = tk.Tk()
            app = FFmpegConfigurator(config_root)
            
            # 居中显示窗口
            config_root.update_idletasks()
            x = (config_root.winfo_screenwidth() // 2) - (config_root.winfo_width() // 2)
            y = (config_root.winfo_screenheight() // 2) - (config_root.winfo_height() // 2)
            config_root.geometry('+{}+{}'.format(x, y))
            
            config_root.mainloop()
            
            # 配置完成后再次检查FFmpeg是否可用
            if FFmpegConfigurator.check_ffmpeg():
                print("FFmpeg配置成功！")
                return True
            else:
                messagebox.showerror("配置失败", "FFmpeg配置失败，请手动下载并安装FFmpeg。")
                return False
                
        except Exception as e:
            print(f"启动FFmpeg配置工具时出错: {e}")
            messagebox.showerror("错误", f"无法启动FFmpeg配置工具: {str(e)}")
            return False


def main():
    root = tk.Tk()
    app = FFmpegConfigurator(root)
    root.protocol("WM_DELETE_WINDOW", app.on_closing)
    
    # 居中显示窗口
    root.update_idletasks()
    x = (root.winfo_screenwidth() // 2) - (root.winfo_width() // 2)
    y = (root.winfo_screenheight() // 2) - (root.winfo_height() // 2)
    root.geometry('+{}+{}'.format(x, y))
    
    root.mainloop()

if __name__ == "__main__":
    main()